package com.xs.tool.json;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.alibaba.fastjson.JSON;
import lombok.*;

import java.lang.reflect.*;
import java.util.*;

public class JsonUtil {
    public static String toJson(Object object) {
        return JSON.toJSONString(object);
    }

    /**
     * 生成类的JSON示例
     */
    @SneakyThrows
    public static String generateJsonExample(Class<?> clazz) {
        try {
            Map<String, Object> example = new LinkedHashMap<>();

            // 处理基础类型
            if (clazz.isPrimitive() || clazz == String.class) {
                return JSONObject.toJSONString(Objects.requireNonNull(generateExampleValue(clazz)));
            } else if (clazz.isRecord()) {
                // 处理Record类型
                RecordComponent[] components = clazz.getRecordComponents();
                for (RecordComponent component : components) {
                    example.put(component.getName(), generateExampleValue(component.getType()));
                }
            } else {
                // 处理普通类
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if (!field.getName().startsWith("$") && !java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
                        example.put(field.getName(), generateExampleValue(field.getType()));
                    }
                }
            }

            ObjectMapper mapper = new ObjectMapper();
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(example);
        } catch (Exception e) {
            return "{\"error\": \"生成JSON示例失败: " + e.getMessage() + "\"}";
        }
    }

    public static <T> String generateJsonExample2(Class<T> clazz) {
        try {
            // 创建实例
            T instance = clazz.getDeclaredConstructor().newInstance();

            // 如果有无参构造函数，尝试设置一些基本字段值
            java.lang.reflect.Field[] fields = clazz.getFields();
            for (java.lang.reflect.Field field : fields) {
                Class<?> type = field.getType();

                Object x = getBaseTypeValue(type);
                if (x != null) {
                    field.set(instance, x);
                } else if (field.getType() == List.class) {
                    ArrayList<Object> value = new ArrayList();
                    ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType();
                    Type actualType = parameterizedType.getActualTypeArguments()[0];
                    Class<?> actualTypeArgument = getRawClass(actualType);
                    String s = generateJsonExample2(actualTypeArgument);
                    value.add(s);
                    field.set(instance, value);
                }else if (field.getType() == Map.class) {
                    field.set(instance, new HashMap<>());
                    field.getGenericType();
                }
            }
            // 转换为JSON字符串
            return JsonUtil.toJson(instance);
        } catch (Exception e) {
            e.printStackTrace();
            return "{}";
        }
    }

    private static Class<?> getRawClass(Type type) {
        return switch (type) {
            case Class aClass -> aClass;
            case ParameterizedType parameterizedType -> (Class<?>) parameterizedType.getRawType();
            case GenericArrayType genericArrayType -> Object[].class;
            case null, default -> Object.class;
        };
    }
    private static Object getBaseTypeValue(Class<?> type) {
        if (type == int.class || type == Integer.class) {
            return 123;
        } else if (type == double.class || type == Double.class) {
            return 123.45;
        } else if (type == long.class || type == Long.class) {
            return 123456789L;
        } else if (type == String.class) {
            return "示例文本";
        } else if (type == boolean.class || type == Boolean.class) {
            return true;
        } else if (type == char.class || type == Character.class) {
            return 'A';
        } else if (type == void.class) {
            return "";
        }
        return null;
    }

    /**
     * 为指定类型生成示例值
     */
    public static Object generateExampleValue(Class<?> type) {
        if (type == int.class || type == Integer.class) {
            return 123;
        } else if (type == double.class || type == Double.class) {
            return 123.45;
        } else if (type == long.class || type == Long.class) {
            return 123456789L;
        } else if (type == String.class) {
            return "示例文本";
        } else if (type == boolean.class || type == Boolean.class) {
            return true;
        } else if (type == char.class || type == Character.class) {
            return 'A';
        } else if (type == void.class) {
            return "";
        } else if (List.class.isAssignableFrom(type)) {
            return new ArrayList<>();
        } else if (Map.class.isAssignableFrom(type)) {
            return new HashMap<>();
        } else {
            return null;
        }
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public static class Test {
        private String name;
        private Integer age;
        private String sex;
    }

    public static <T> String obtainUpdateJson(T po, T update) {
        if (po == null || update == null || po.getClass() != update.getClass()) {
            throw new RuntimeException("po 和 addValue 类型不一致或为空");
        }

        Map<String, Object> result = new HashMap<>();
        Class<?> aClass = po.getClass();

        for (Field field : aClass.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object poValue = field.get(po);
                Object updateValue = field.get(update);

                if (!Objects.equals(poValue, updateValue)) {
                    result.put(field.getName(), updateValue);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("字段访问失败: " + field.getName(), e);
            }
        }

        return JSON.toJSONString(result);
    }
}
